#ifndef QMODEL_H
#define QMODEL_H

#include <QObject>
#include <QDebug>
#include <QMetaProperty>
#include <QJsonObject>

// 定义模型的属性、数据库字段
#define Q_DB_COLUMN(type,name) \
    Q_PROPERTY(type name READ get##name WRITE set##name) \
    public: \
    type name; \
    public: \
    type get##name() const { \
    return name; \
    } \
    void set##name(type value) { \
    name = value; \
    }

// 定义克隆函数
#define Q_CLONE_CLASS(clsName) \
    public: \
    clsName(const clsName& other):QModel(){ \
    QModel::clone(other); \
    } \
    clsName& operator=(const clsName& other){ \
    QModel::clone(other); \
    return *this; \
    }

// 模型
class QModel : public QObject
{
    Q_OBJECT
public:
    explicit QModel(QObject *parent = 0):QObject(parent){
        this->ignore.append("objectName");
    }

    // 克隆函数
    QModel(const QModel& other):QObject(){
        this->clone(other);
    }

    // 赋值函数
    QModel& operator=(const QModel& other){
        this->clone(other);
        return *this;
    }

private:
    // 忽略的属性列表
    QList<QString> ignore;

public:
    // 判断继承关系
    virtual bool hasClass(QString name){
        if(name.isEmpty()){
            return false;
        }
        bool flag = false;
        auto meta = this->metaObject();
        do {
            flag = meta->className() == name;
            if(flag){
                break;
            }
            meta = meta->superClass();
        } while (meta);
        return flag;
    }

    // 判断属性
    virtual bool hasProperty(QByteArray name){
        auto meta = this->metaObject();
        return meta->indexOfProperty(name.data()) != -1;
    }

    // 复制属性
    virtual void clone(const QModel& other){
        auto meta = this->metaObject();
        auto o = other.metaObject();

        for(int i=0;i<meta->propertyCount();i++){
            auto item = meta->property(i);
            auto name = item.name();

            // 内部忽略
            if(this->ignore.contains(name)){
                continue;
            }

            auto value = QVariant();
            auto idx = o->indexOfProperty(name);
            if(idx == -1){
                // 忽略大小写
                auto lower = QString(name).toLower().toUtf8();
                idx = o->indexOfProperty(lower);
            }
            if(idx == -1){
                continue;
            }

            // 赋值
            value = o->property(idx).read(&other);
            this->setProperty(name,value);
        }
    }

    // 从 QJsonObject 赋值属性值
    virtual void json(QJsonObject json){
        if(json.isEmpty()){
            return;
        }
        auto meta = this->metaObject();
        for(int i=0;i<meta->propertyCount();i++){
            auto item = meta->property(i);
            auto name = item.name();

            // 内部忽略
            if(this->ignore.contains(name)){
                continue;
            }

            auto has = false;
            auto value = QVariant();
            if(json.contains(name)){
                has = true;
                value = json.value(name).toVariant();
            }

            // 忽略大小写
            auto lower = QString(name).toLower();
            if (!has && json.contains(lower)){
                has = true;
                value = json.value(lower).toVariant();
            }
            if(!has){
                continue;
            }

            // 赋值
            this->setProperty(name,value);
        }
    }

    // 从 QVariantMap 赋值属性值
    virtual void variant(QVariantMap map){
        if(map.isEmpty()){
            return;
        }
        auto meta = this->metaObject();
        for(int i=0;i<meta->propertyCount();i++){
            auto item = meta->property(i);
            auto name = item.name();

            // 内部忽略
            if(this->ignore.contains(name)){
                continue;
            }

            auto has = false;
            auto value = QVariant();
            if(map.contains(name)){
                has = true;
                value = map.value(name);
            }

            // 忽略大小写
            auto lower = QString(name).toLower();
            if (!has && map.contains(lower)){
                has = true;
                value = map.value(lower);
            }
            if(!has){
                continue;
            }

            // 赋值
            this->setProperty(name,value);
        }
    }
};

#endif // QMODEL_H
